<?php

namespace App\Http\Service\Baoliao;

use App\Models\Baoliaopostback;
use App\Models\Baoliaopost;
use App\Models\Baoliaolike;
use App\Models\Baoliaocollect;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use App\Http\Service\BaseService;
use App\Http\Service\ContentScoringService;
use App\Models\Baoliaolog;
use App\Http\Service\UserService;
use App\Http\Service\MoneyService;
use App\Http\Service\PlatformsService;
use App\Http\Service\SiteConfigService;
use App\Http\Service\PostaiService;
use App\Http\Service\Brand\CategorymappingService;
use App\Http\Service\Brand\BrandmappingService;
use App\Models\Doubanpostproduct;
use App\Models\Doubanpost;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

use App\Http\Service\Douban\DoubanpostproductService;
class Baoliao3Service  extends BaseService
{
    private $url;
    private $getInfo;
    private $model;
    public $URL_MAP;
    public function __construct(Baoliaopost $model,Baoliaolog $baoliaolog,UserService  $userService,PlatformsService $platformsService,SiteConfigService $siteConfigService,Doubanpostproduct $doubanpostproduct,DoubanpostproductService $DoubanpostproductService,PostaiService $postaiService,Doubanpost $doubanpost,MoneyService $moneyService,CategorymappingService $categorymappingService,BrandmappingService $brandmappingService,Baoliaopostback $baoliaopostback)
    {
        parent::__construct();
        $this->model = $model;
        $this->userService=$userService;
        $this->platformsService=$platformsService;
        $this->baoliaolog=$baoliaolog;
        $this->siteConfigService=$siteConfigService;
        $this->doubanpostproduct=$doubanpostproduct;
        $this->DoubanpostproductService=$DoubanpostproductService;
        $this->url=config('myurl.link-batch-parse.url');
        $this->getInfo=config('myurl.getInfo');
        $this->URL_MAP=config('myurl.URL_MAP');
        $this->postaiService=$postaiService;
        $this->doubanpost=$doubanpost;
        $this->moneyService=$moneyService;
        $this->categorymappingService=$categorymappingService;
        $this->brandmappingService=$brandmappingService;
        $this->baoliaopostback=$baoliaopostback;

    }
    public function perfectInfo3($request, $data = [])
    {
        // 增加内存限制防止内存溢出
        ini_set('memory_limit', '512M');
        
        $cacheKey = 'baoliao_check:' . $data['platform_name'] . ':' . $data['product_unique_id'];
        $lockKey = 'baoliao_submit:' . $data['product_unique_id'];
        
        try {
            // 1. 快速缓存检查 - 使用更高效的方式
            if (Cache::get($cacheKey) === 'exists') {
                $this->error("该商品已被其他人爆料，请稍后再试");
            }

            // 2. 数据预处理优化
            $jsonData = $request->json()->all();
            // 限制JSON数据大小，防止内存溢出
            if (is_array($jsonData) && count($jsonData) > 50) {
                $jsonData = array_slice($jsonData, 0, 50);
            }
            $data['json_data'] = json_encode($jsonData, JSON_UNESCAPED_UNICODE);
            
            $data['start_time'] = completeDateTime($data['start_time']);
            $data['end_time'] = completeDateTime($data['end_time']);
            $data['create_time'] = $data['update_time'] = date("Y-m-d H:i:s");

            // 3. 浏览量设置优化
            $type = $data['type'] ?? null;
            if (in_array($type, ['2','4'])) {
                // 使用静态配置或缓存，避免重复查询数据库
                $viewRange = Cache::remember('view_count_range', 3600, function () {
                    $siteConfig = $this->siteConfigService->getList('4');
                    return [
                        'min' => $siteConfig['content']['min'] ?? 0,
                        'max' => $siteConfig['content']['max'] ?? 1000
                    ];
                });
                $data['view_count'] = getRandomInRange($viewRange['min'], $viewRange['max']);
            }
            $data['view_count'] = $data['view_count'] ?? 0;

            // 4. 使用Redis原子操作确保并发安全
            return $this->processWithRedisLock($data, $cacheKey, $lockKey);
            
        } catch (\Exception $e) {
            // 确保锁被释放
            Cache::forget($lockKey);
            \Log::error('爆料提交异常: ' . $e->getMessage(), [
                'product_unique_id' => $data['product_unique_id']
            ]);
            $this->error('系统繁忙，请稍后重试');
        } finally {
            // 强制垃圾回收
            gc_collect_cycles();
        }
    }

    /**
     * 使用 Redis 原子锁处理高并发
     */
    protected function processWithRedisLock($data, $cacheKey, $lockKey)
    {
        $maxRetries = 3;
        
        for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
            try {
                // 使用Redis setnx 实现分布式锁
                $lockAcquired = Cache::add($lockKey, 1, 5); // 5秒锁超时
                
                if (!$lockAcquired) {
                    if ($attempt === $maxRetries) {
                        $this->error("系统繁忙，请稍后重试");
                    }
                    usleep(100000 * $attempt); // 递增等待
                    continue;
                }

                // 在锁内再次检查缓存
                if (Cache::get($cacheKey) === 'exists') {
                    Cache::forget($lockKey);
                    $this->error("该商品已被其他人爆料，请稍后再试");
                }

                // 执行数据库操作
                $result = DB::transaction(function () use ($data, $cacheKey) {
                    return $this->processDatabaseOperations($data, $cacheKey);
                }, 3);

                // 释放锁
                Cache::forget($lockKey);
                
                return $result;

            } catch (\Exception $e) {
                // 释放锁
                Cache::forget($lockKey);
                
                if ($this->shouldRetry($e, $attempt, $maxRetries)) {
                    usleep(100000 * pow(2, $attempt)); // 指数退避
                    continue;
                }
                throw $e;
            }
        }
    }

    /**
     * 数据库操作分离
     */
    protected function processDatabaseOperations($data, $cacheKey)
    {
        // 1. 检查现有爆料 - 使用更高效的查询
        $existingBaoliao = DB::table('vw_baoliao_post_all')
            ->where('platform_name', $data['platform_name'])
            ->where('product_unique_id', $data['product_unique_id'])
            ->where('is_expired', 2)
            ->select('id', 'start_time', 'end_time')
            ->orderBy('id', 'desc')
            ->first();
        //dd($existingBaoliao);
        

        if ($existingBaoliao) {
            $currentTime = time();
            $startTime = strtotime($existingBaoliao->start_time);
            $endTime = strtotime($existingBaoliao->end_time);
            
            if ($currentTime >= $startTime && $currentTime <= $endTime) {
                // 设置缓存并返回错误
                Cache::put($cacheKey, 'exists', 300); // 5分钟缓存
                $this->error("该商品已被其他人爆料,可以去评论【{$existingBaoliao->id}】");
            } else {
                // 标记过期 - 使用更安全的更新
                $updated = $this->model->where('id', $existingBaoliao->id)
                    ->where('is_expired', 2) // 添加条件防止并发更新
                    ->update([
                        'is_expired' => 1,
                        'update_time' => date("Y-m-d H:i:s")
                    ]);
                
                if (!$updated) {
                    throw new \Exception('并发更新冲突，记录已被其他进程修改');
                }
            }
        }

        #dd($data);
        // 2. 插入新数据
        $newId = $this->model->insertGetId($data);

        #插入当前数据
        #$data2=$data;
        #$data2['id']=$newId;

        if (!$newId) {
            throw new \Exception('数据插入失败');
        }
        #$this->baoliaopostback->insertGetId($data2);
        // 3. 异步清理任务 - 使用更轻量的方式
        $this->dispatchCleanupJob($data);

        // 4. 设置成功缓存
        Cache::put($cacheKey, 'exists', 600); // 10分钟缓存

        $this->success(['id' => $newId]);
    }

    /**
     * 异步清理任务优化
     */
    protected function dispatchCleanupJob77777($data)
    {
        // 使用更轻量的队列任务
        dispatch(function () use ($data) {
            try {
                // 分批清理，避免大事务
                $chunkSize = 100;
                
                // 修复：使用正确的表名 - 通过模型查询
                $this->model
                    ->where('is_expired', 2)
                    ->where('platform_name', $data['platform_name'])
                    ->where('product_unique_id', '!=', $data['product_unique_id'])
                    ->where('create_time', '<', now()->subHours(1))
                    ->orderBy('id')
                    ->chunk($chunkSize, function ($duplicates) {
                        $keepId = $duplicates->first()->id; // 保留最新的
                        
                        // 使用模型进行更新
                        $this->model
                            ->whereIn('id', $duplicates->pluck('id')->toArray())
                            ->where('id', '!=', $keepId)
                            ->update(['is_expired' => 1]);
                    });
                    
            } catch (\Exception $e) {
                \Log::error('清理任务失败: ' . $e->getMessage());
            }
        })->delay(now()->addSeconds(10))->onQueue('low'); // 延迟并使用低优先级队列
    }
    protected function dispatchCleanupJob($data)
    {
        dispatch(function () use ($data) {
            try {
                $this->conservativeCleanup($data);
            } catch (\Exception $e) {
                \Log::error('清理任务失败: ' . $e->getMessage(), [
                    'platform_name' => $data['platform_name'] ?? '',
                    'product_unique_id' => $data['product_unique_id'] ?? ''
                ]);
            }
        })->delay(now()->addMinutes(5))->onQueue('low'); // 更长的延迟，确保数据稳定
    }

    /**
     * 保守的清理策略 - 每次只清理少量数据
     */
    protected function conservativeCleanup($data)
    {
        $limit = 10; // 每次只处理10条
        
        try {
            // 查找需要清理的记录（限制数量）
            $toCleanup = $this->model
                ->where('is_expired', 2)
                ->where('platform_name', $data['platform_name'])
                ->where('product_unique_id', $data['product_unique_id'])
                ->where('create_time', '<', now()->subHours(1))
                ->orderBy('id', 'desc')
                ->skip(1) // 跳过最新的一个
                ->take($limit)
                ->get();
                
            if ($toCleanup->isEmpty()) {
                return;
            }
            
            $ids = $toCleanup->pluck('id')->toArray();
            
            // 单次更新
            $affected = $this->model
                ->whereIn('id', $ids)
                ->update([
                    'is_expired' => 1,
                    'update_time' => now()
                ]);
                
            \Log::info('保守清理完成', [
                'attempted' => count($ids),
                'affected' => $affected
            ]);
            
        } catch (\Exception $e) {
            \Log::warning('保守清理失败', [
                'error' => $e->getMessage(),
                'platform_name' => $data['platform_name'],
                'product_unique_id' => $data['product_unique_id']
            ]);
        }
    }
    /**
     * 判断是否应该重试
     */
    protected function shouldRetry($exception, $attempt, $maxRetries)
    {
        if ($attempt >= $maxRetries) {
            return false;
        }
        
        $retryableErrors = [
            'Deadlock',
            'Lock wait timeout',
            'Connection',
            'Serialization failure',
            'Base table or view not found' // 添加表不存在错误重试
        ];
        
        foreach ($retryableErrors as $error) {
            if (str_contains($exception->getMessage(), $error)) {
                return true;
            }
        }
        
        return false;
    }

    /**
     * 获取正确的表名
     */
    protected function getTableName()
    {
        // 通过模型获取正确的表名
        return $this->model->getTable();
    }

    /**
     * 安全的数据库查询方法
     */
    protected function safeQuery($callback)
    {
        try {
            return $callback();
        } catch (\Illuminate\Database\QueryException $e) {
            if (str_contains($e->getMessage(), 'Base table or view not found')) {
                \Log::error('数据库表不存在: ' . $this->getTableName());
                $this->error('系统配置错误，请联系管理员');
            }
            throw $e;
        }
    }
}
